import { Inject, Service } from "typedi";
import { Contract, ContractItem } from "./contracts/entity";
import { AuthService } from "./AuthService";
import { database, esi } from "./index";
import type { PageFetchParams } from "@chulei-ui/components";
import type { Token } from "@scvzerng/esi-163";
import type { Repository } from "typeorm";

@Service()
export class ContractService {
  private contractRepository: Repository<Contract>;
  private contractItemRepository: Repository<ContractItem>;
  @Inject(() => AuthService)
  private authService!: AuthService;
  constructor() {
    this.contractRepository = database.getRepository(Contract);
    this.contractItemRepository = database.getRepository(ContractItem);
  }

  /**
   * 同步玩家的合同信息
   * @param playerId
   */
  public async syncContract(playerId: number) {
    const token = await this.authService.getAccessTokenFromPlayerId(playerId);
    const accessToken = { access_token: token } as Token;
    let page = 1;
    while (true) {
      const contracts = await esi.contracts.personalContracts(accessToken, playerId, page);
      if (!contracts || contracts.length === 0) break;
      for (const contract of contracts) {
        let localContract = await this.contractRepository.findOne({
          where: { contract_id: contract.contract_id },
        });
        //过滤掉已完成并且本地已经保存过的
        if (localContract) continue;
        if (!localContract) {
          localContract = Contract.formContract(contract);
          localContract.issuer_name = (await esi.character.info(contract.issuer_id))?.name;
          if (!contract.for_corporation && contract.acceptor_id) {
            localContract.acceptor_name = (await esi.character.info(contract.acceptor_id))?.name;
          }
          const saved = await new Promise<Contract>((resolve) => {
            requestIdleCallback(async () => {
              const saved = await this.contractRepository.save(localContract!);
              resolve(saved);
            });
          });
          const contractItems = await esi.contracts.contract(accessToken, playerId, contract.contract_id);
          for (const contractItem of contractItems ?? []) {
            const localContractItem = ContractItem.fromContractItem(contractItem);
            localContractItem.contract = saved;
            await new Promise<void>((resolve) => {
              requestIdleCallback(() => {
                this.contractItemRepository.save(localContractItem);
                resolve();
              });
            });
          }
        } else {
          await this.contractRepository.save(Contract.formContract(contract));
        }
      }
      page = page + 1;
    }
  }

  public async getContracts(playerId: number, page: PageFetchParams) {
    return this.contractRepository.find({
      where: [
        {
          assignee_id: playerId,
        },
        {
          issuer_id: playerId,
        },
      ],
      relations: ["items"],
      order: {
        contract_id: "desc",
      },
      skip: page.startRow,
      take: page.pageSize,
    });
  }

  public async getContract(contractId: number) {
    return this.contractRepository.findOne({
      where: {
        contract_id: contractId,
      },
      relations: ["items"],
    });
  }

  public async save(contract: Contract) {
    await this.contractRepository.save(contract);
    return this.getContract(contract.contract_id);
  }
}
